﻿#include "function_bottom_match.h"
void bottomMatch (HObject ho_image, HObject *ho_xld_show, HTuple hv_model, HTuple *hv_score,
    HTuple *hv_ret)
{

  // Local iconic variables
  HObject  ho_ImageResult, ho_ImageEquHisto;

  // Local control variables
  HTuple  hv_Width, hv_Height, hv_RowC, hv_ColumnC;
  HTuple  hv_AngleC, hv_ScaleC, hv_HomMat2D;

  GetImageSize(ho_image, &hv_Width, &hv_Height);
  MultImage(ho_image, ho_image, &ho_ImageResult, 0.01, 0);
  EquHistoImage(ho_ImageResult, &ho_ImageEquHisto);
  FindScaledShapeModel(ho_ImageEquHisto, hv_model, -(HTuple(180).TupleRad()), HTuple(360).TupleRad(),
      1.0, 1.02, 0.3, 1, 0.0, "least_squares", 0, 0.0, &hv_RowC, &hv_ColumnC, &hv_AngleC,
      &hv_ScaleC, &(*hv_score));
  GetShapeModelContours(&(*ho_xld_show), hv_model, 1);
  VectorAngleToRigid(0, 0, 0, hv_RowC, hv_ColumnC, hv_AngleC, &hv_HomMat2D);
  HomMat2dScale(hv_HomMat2D, hv_ScaleC, hv_ScaleC, hv_RowC, hv_ColumnC, &hv_HomMat2D);

  AffineTransContourXld((*ho_xld_show), &(*ho_xld_show), hv_HomMat2D);
    (*hv_ret) = 1;
}

void createBottomMatch (HObject ho_image, HObject *ho_xld_show, HTuple *hv_ret, HTuple *hv_model)
{

  // Local iconic variables
  HObject  ho_Region, ho_ConnectedRegions, ho_SelectedRegionsCircle;
  HObject  ho_RegionFillUp, ho_RegionDilation, ho_PolarTransImage;
  HObject  ho_ImageResult, ho_Regions, ho_RegionComplement;
  HObject  ho_ConnectedRegions1, ho_RegionClosing, ho_RegionTrans;
  HObject  ho_SelectedRegionsOut, ho_SortedRegions, ho_ObjectSelected;
  HObject  ho_RegionDilation1, ho_ImageReduced, ho_Edges, ho_SmoothedContours;
  HObject  ho_ContoursSplit, ho_ObjectSelected1, ho_ContCircle;
  HObject  ho_ObjectSelected2, ho_ContourLine, ho_ObjectsConcatXLD;
  HObject  ho_ModelContours, ho_ObjectSelectedCircle, ho_ImageResult1;
  HObject  ho_ContoursSet, ho_ContoursAffineTrans, ho_XYTransContour;

  // Local control variables
  HTuple  hv_Width, hv_Height, hv_RadiusAdd, hv_PolarWidth;
  HTuple  hv_Row, hv_Column, hv_RadiusInner, hv_Row2, hv_Column2;
  HTuple  hv_Radius2, hv_StartPhi, hv_EndPhi, hv_PointOrder1;
  HTuple  hv_RowBegin, hv_ColBegin, hv_RowEnd, hv_ColEnd;
  HTuple  hv_Nr, hv_Nc, hv_Dist, hv_ModelID, hv_RowC, hv_ColumnC;
  HTuple  hv_AngleC, hv_ScaleC, hv_Score, hv_j, hv_HomMat2D;
  HTuple  hv_model_row, hv_model_column, hv_model_angle, hv_model_scale;
  HTuple  hv_model_score, hv_Message;

  GetImageSize(ho_image, &hv_Width, &hv_Height);
  hv_RadiusAdd = 100.5;
  hv_PolarWidth = 5000;

  Threshold(ho_image, &ho_Region, 0, 60);
  Connection(ho_Region, &ho_ConnectedRegions);
  SelectShape(ho_ConnectedRegions, &ho_SelectedRegionsCircle, (HTuple("roundness").Append("ra")),
      "and", (HTuple(0.8).Append(1000)), (HTuple(1.0).Append(1300)));
  FillUp(ho_SelectedRegionsCircle, &ho_RegionFillUp);
  SmallestCircle(ho_RegionFillUp, &hv_Row, &hv_Column, &hv_RadiusInner);
  DilationCircle(ho_RegionFillUp, &ho_RegionDilation, hv_RadiusAdd);
  PolarTransImageExt(ho_image, &ho_PolarTransImage, hv_Row, hv_Column, HTuple(360).TupleRad(),
      -(HTuple(0).TupleRad()), hv_RadiusInner, hv_RadiusInner+hv_RadiusAdd, hv_PolarWidth,
      hv_RadiusAdd, "nearest_neighbor");

  MultImage(ho_PolarTransImage, ho_PolarTransImage, &ho_ImageResult, 0.08, 0);
  Regiongrowing(ho_ImageResult, &ho_Regions, 1, 1, 3, 5000);
  Complement(ho_Regions, &ho_RegionComplement);
  Connection(ho_RegionComplement, &ho_ConnectedRegions1);
  ClosingCircle(ho_ConnectedRegions1, &ho_RegionClosing, 35.5);
  ShapeTrans(ho_RegionClosing, &ho_RegionTrans, "convex");
  SelectShape(ho_RegionTrans, &ho_SelectedRegionsOut, (HTuple("rect2_len1").Append("rect2_len2")),
      "and", (HTuple(80).Append(15)), (HTuple(120).Append(30)));

  SortRegion(ho_SelectedRegionsOut, &ho_SortedRegions, "first_point", "true", "column");
  SelectObj(ho_SortedRegions, &ho_ObjectSelected, 1);
  DilationCircle(ho_ObjectSelected, &ho_RegionDilation1, 3.5);
  ReduceDomain(ho_ImageResult, ho_RegionDilation1, &ho_ImageReduced);
  EdgesSubPix(ho_ImageReduced, &ho_Edges, "canny", 1, 60, 120);
  SmoothContoursXld(ho_Edges, &ho_SmoothedContours, 5);
  SegmentContoursXld(ho_SmoothedContours, &ho_ContoursSplit, "lines_ellipses", 5,
      40, 20);
  SelectObj(ho_ContoursSplit, &ho_ObjectSelected1, 1);
  FitCircleContourXld(ho_ObjectSelected1, "algebraic", -1, 0, 0, 3, 2, &hv_Row2,
      &hv_Column2, &hv_Radius2, &hv_StartPhi, &hv_EndPhi, &hv_PointOrder1);
  GenCircleContourXld(&ho_ContCircle, hv_Row2, hv_Column2, hv_Radius2, (hv_StartPhi.TupleConcat(hv_EndPhi)).TupleMin(),
      (hv_StartPhi.TupleConcat(hv_EndPhi)).TupleMax(), "positive", 1);
  SelectObj(ho_ContoursSplit, &ho_ObjectSelected2, 2);
  FitLineContourXld(ho_ObjectSelected2, "tukey", -1, 0, 5, 2, &hv_RowBegin, &hv_ColBegin,
      &hv_RowEnd, &hv_ColEnd, &hv_Nr, &hv_Nc, &hv_Dist);
  GenContourPolygonXld(&ho_ContourLine, hv_RowBegin.TupleConcat(hv_RowEnd), hv_ColBegin.TupleConcat(hv_ColEnd));
  ConcatObj(ho_ContCircle, ho_ContourLine, &ho_ObjectsConcatXLD);

  CreateScaledShapeModelXld(ho_ObjectsConcatXLD, "auto", -(HTuple(1).TupleRad()),
      HTuple(2).TupleRad(), "auto", 0.9, 1.1, "auto", "auto", "ignore_local_polarity",
      5, &hv_ModelID);
  GetShapeModelContours(&ho_ModelContours, hv_ModelID, 1);
  SelectObj(ho_ModelContours, &ho_ObjectSelectedCircle, 1);
  MultImage(ho_PolarTransImage, ho_PolarTransImage, &ho_ImageResult1, 0.03, 0);
  FindScaledShapeModel(ho_ImageResult1, hv_ModelID, -(HTuple(1).TupleRad()), HTuple(2).TupleRad(),
      0.95, 1.05, 0.85, 8, 0.0, "least_squares", 0, 0.9, &hv_RowC, &hv_ColumnC, &hv_AngleC,
      &hv_ScaleC, &hv_Score);

  GenEmptyObj(&ho_ContoursSet);
  {
  HTuple end_val42 = (hv_Score.TupleLength())-1;
  HTuple step_val42 = 1;
  for (hv_j=0; hv_j.Continue(end_val42, step_val42); hv_j += step_val42)
  {
    VectorAngleToRigid(0, 0, 0, HTuple(hv_RowC[hv_j]), HTuple(hv_ColumnC[hv_j]),
        HTuple(hv_AngleC[hv_j]), &hv_HomMat2D);
    AffineTransContourXld(ho_ObjectSelectedCircle, &ho_ContoursAffineTrans, hv_HomMat2D);
    ConcatObj(ho_ContoursSet, ho_ContoursAffineTrans, &ho_ContoursSet);
  }
  }



  PolarTransContourXldInv(ho_ContoursSet, &ho_XYTransContour, hv_Row, hv_Column,
      HTuple(360).TupleRad(), -(HTuple(0).TupleRad()), hv_RadiusInner, hv_RadiusInner+hv_RadiusAdd,
      hv_PolarWidth, hv_RadiusAdd, hv_Width, hv_Height);
  CreateScaledShapeModelXld(ho_XYTransContour, "auto", -(HTuple(180).TupleRad()),
      HTuple(360).TupleRad(), "auto", 1.0, 1.02, "auto", "auto", "ignore_local_polarity",
      5, &(*hv_model));
  GetShapeModelContours(&ho_ModelContours, (*hv_model), 1);
  FindScaledShapeModel(ho_image, (*hv_model), -(HTuple(180).TupleRad()), HTuple(360).TupleRad(),
      0.9, 1.1, 0.5, 1, 0.5, "least_squares", 0, 0.9, &hv_model_row, &hv_model_column,
      &hv_model_angle, &hv_model_scale, &hv_model_score);

  if (0 != (int((hv_model_score.TupleLength())<0)))
  {
    (*hv_ret) = -1;
    hv_Message = "model_match not match";
    return;
  }
  VectorAngleToRigid(0, 0, 0, hv_model_row, hv_model_column, hv_model_angle, &hv_HomMat2D);
  HomMat2dScale(hv_HomMat2D, hv_model_scale, hv_model_scale, hv_model_row, hv_model_column,
      &hv_HomMat2D);


  AffineTransContourXld(ho_ModelContours, &(*ho_xld_show), hv_HomMat2D);

  (*hv_ret) = 1;




}

DetectionBottomMatch::DetectionBottomMatch(QDialog* parent, QSettings* qsettings, QString section, QString dir) : QDialog(parent)
{
	m_dir = dir + "/" + section;
	m_qsettings = qsettings;

	m_section = section;

	/*m_create_shape_model = new FunctionCreateShapeModel(this, dir, section);*/

	this->setWindowTitle(("find shape model"));
	QRect desktop_rect = QApplication::desktop()->geometry();
	double ratio_x = desktop_rect.width() / 1920.0;
	double ratio_y = desktop_rect.height() / 1080.0;

	move(0, 0);
	this->setFixedSize(1920 * ratio_x, 1010 * ratio_y);

	QHBoxLayout* hlayout = new QHBoxLayout();
	this->setLayout(hlayout);



	QFrame* p = new QFrame(this);
	QSize control_size(240 * ratio_x, 40 * ratio_y);
	p->setFrameShape(QFrame::WinPanel);
	p->move(0 * ratio_x, 0 * ratio_y);
	p->setFixedSize(600 * ratio_x, 800 * ratio_y);

	hlayout->addWidget(p);

	QGridLayout *qgridLayout = new QGridLayout();
	p->setLayout(qgridLayout);

	int index = 0;

	QSize ButtonSize(220 * ratio_x, 40 * ratio_y);


	m_qlabel_score_standard = new QLabel();
	m_qlabel_score_standard->setText("Match Score");
	m_qlabel_score_standard->setFixedSize(control_size);
	qgridLayout->addWidget(m_qlabel_score_standard, index, 0);
	m_qdoublespinbox_score_standard = new QDoubleSpinBox();
	m_qdoublespinbox_score_standard->setFixedSize(control_size);
	m_qdoublespinbox_score_standard->setMinimum(0);
	m_qdoublespinbox_score_standard->setMaximum(1);
	qgridLayout->addWidget(m_qdoublespinbox_score_standard, index, 1);
	index++;

//	QPushButton* p_QPushButton = new QPushButton(this);
//	p_QPushButton->setFixedSize(control_size);
//	p_QPushButton->setText("Draw ROI");
//	connect(p_QPushButton, &QPushButton::clicked, this, [=]() {
//		m_view->m_pixmapItem->m_shape_type = 1;
//		m_view->m_pixmapItem->m_color = Qt::blue;
//		m_view->m_pixmapItem->m_bool_filled = false;
//	});
//	qgridLayout->addWidget(p_QPushButton, index, 0);


//	p_QPushButton = new QPushButton(this);
//	p_QPushButton->setFixedSize(control_size);
//	p_QPushButton->setText("Delete ROI");
//	qgridLayout->addWidget(p_QPushButton, index, 1);
//	connect(p_QPushButton, &QPushButton::clicked, this, [=]() {
//		for (GraphicsShapeRectangleCirce *item : m_vector_graphics_shape_rectangle) {
//			m_view->scene()->removeItem(item);
//			delete item;
//		}
//		m_vector_graphics_shape_rectangle.clear();
//	});
//	index++;
	

	m_pushbutton_create_new_model = new QPushButton(this);
	m_pushbutton_create_new_model->setFixedSize(control_size);
	m_pushbutton_create_new_model->setText("Create Model");
    connect(m_pushbutton_create_new_model, &QPushButton::clicked, this, &DetectionBottomMatch::createModel);
	qgridLayout->addWidget(m_pushbutton_create_new_model, index, 0);

	m_pushbutton_show_model = new QPushButton(this);
	m_pushbutton_show_model->setFixedSize(control_size);
	m_pushbutton_show_model->setText("Show Model");
    connect(m_pushbutton_show_model, &QPushButton::clicked, this, &DetectionBottomMatch::showModel);
	qgridLayout->addWidget(m_pushbutton_show_model, index, 1);
	index++;

	m_pushbutton_show_orign_image = new QPushButton(this);
	m_pushbutton_show_orign_image->setFixedSize(control_size);
	m_pushbutton_show_orign_image->setText("Show Orign Image");
	connect(m_pushbutton_show_orign_image, &QPushButton::clicked, this, [=]() {
		QImage q_image = matToQImage(m_image);
		m_view->setImage(q_image, "");
		return true;
	});
	qgridLayout->addWidget(m_pushbutton_show_orign_image, index, 0);
	m_pushbutton_detection = new QPushButton(this);
	m_pushbutton_detection->setFixedSize(control_size);
	m_pushbutton_detection->setText("Detection");
    connect(m_pushbutton_detection, &QPushButton::clicked, this, &DetectionBottomMatch::detectionImage);
	qgridLayout->addWidget(m_pushbutton_detection, index, 1);
	index++;

	m_pushbutton_save_parameter = new QPushButton(this);
	m_pushbutton_save_parameter->setFixedSize(control_size);
	m_pushbutton_save_parameter->setText("Save");
    connect(m_pushbutton_save_parameter, &QPushButton::clicked, this, &DetectionBottomMatch::saveParameter);
	qgridLayout->addWidget(m_pushbutton_save_parameter, index, 0);

	m_pushbutton_return = new QPushButton(this);
	m_pushbutton_return->setFixedSize(control_size);
	m_pushbutton_return->setText("Exit");
	qgridLayout->addWidget(m_pushbutton_return, index, 1);
	connect(m_pushbutton_return, &QPushButton::clicked, this, [=]() {
		this->hide();
	});



	{//加入图像显示
		QVBoxLayout* view_layout = new QVBoxLayout();
		view_layout->setMargin(0);
		m_view = new QtQGraphicsView(this);
		m_view->setFixedSize(1250 * ratio_x, 900 * ratio_y);
//		connect(m_view->m_pixmapItem, &QtQGraphicsPixmapItem::drawRectangleFinish, this, [=](QGraphicsItem* p, int draw_type)
//		{
//			if (draw_type == 1)
//				m_vector_graphics_shape_rectangle.push_back((GraphicsShapeRectangleCirce*)p);
//		});
		connect(m_view->m_pixmapItem, &QtQGraphicsPixmapItem::sendMessage, this, [=](QPointF pos, QString message)
		{
			Q_UNUSED(pos);
			m_view_pixel_qlabel->setText(message);
		});
		view_layout->addWidget(m_view);
		m_view_pixel_qlabel = new QLabel(this);
		m_view_pixel_qlabel->setAlignment(Qt::AlignRight);
		m_view_pixel_qlabel->setText("");
		m_view_pixel_qlabel->setFixedSize(1250 * ratio_x, 20 * ratio_y);
		view_layout->addWidget(m_view_pixel_qlabel);
		hlayout->addLayout(view_layout);
	}
	loadParameter();
}

DetectionBottomMatch::~DetectionBottomMatch()
{
	;
}

bool DetectionBottomMatch::detection(HObject image_in, QString& message)
{
	try
	{
		if (m_model.Length() == 0)
		{
			message = "no model";
			return false;
		}

		HTuple hv_ret, hv_max_value;
        bottomMatch(image_in, &m_xld_show, m_model, &hv_max_value, &hv_ret);


		int ret = hv_ret[0].I();

		if (ret > 0)
		{
			double score = hv_max_value[0].D();


			if (score > m_score_standard)
				return true;
			else
			{
                message = "flank match NG" +  QString::number(score);
				return false;
			}
		}
		else
		{
            message = "lrank match NG no find";
			return false;
		}
	}
	catch (HException &HDevExpDefaultException)
	{
		message = HDevExpDefaultException.ErrorMessage();
		return false;
	}

	return true;
}

void DetectionBottomMatch::detectionImage()
{
	if (m_image.empty())
	{
		QMessageBox::information(nullptr, "", "no image");
		return;
	}

	QString message;
	HObject image = matToHImage(m_image);
	bool state = detection(image, message);


	if (state)
		message += "OK";
	else
		message += "NG";
	Mat image_show = m_image.clone();
	draw(image_show, image_show);

	QImage q_image = matToQImage(image_show);

	m_view->setImage(q_image, message);

}

void DetectionBottomMatch::draw(Mat image_in, Mat& image_out)
{
	if (image_in.empty())
	{
		return;
	}
	if (image_in.channels() == 1)
	{
		cvtColor(image_in, image_in, COLOR_GRAY2BGR);
	}


	image_out = drawXld(image_in, m_xld_show, Scalar(0, 255, 0));
	m_xld_show.Clear();
}

void DetectionBottomMatch::loadParameter()
{
//	int roi_number = m_qsettings->value(m_section + "/" + "roi_number", 0).toInt();
//	if (roi_number > 0)
//	{
//		int i = 0;
//		row1 = m_qsettings->value(m_section + "/" + "ROI" + QString::number(i) + "row1", 100).toInt();
//		column1 = m_qsettings->value(m_section + "/" + "ROI" + QString::number(i) + "column1", 100).toInt();
//		row2 = m_qsettings->value(m_section + "/" + "ROI" + QString::number(i) + "row2", 200).toInt();
//		column2 = m_qsettings->value(m_section + "/" + "ROI" + QString::number(i) + "column2", 200).toInt();

//		GraphicsShapeRectangleCirce* p = new GraphicsShapeRectangleCirce(column1, row1, column2 - column1, row2 - row1, Qt::blue);
//		p->setShapeType(0);
//		p->setFilled(false);
//		p->setZValue(101);
//		m_view->m_scene->addItem(p);

//		m_vector_graphics_shape_rectangle.push_back(p);
//	}

	m_score_standard = m_qsettings->value(m_section + "/" + "m_score_standard").toDouble();

	m_qdoublespinbox_score_standard->setValue(m_score_standard);

	try {
		ReadShapeModel((m_dir + "/model.shm").toLocal8Bit().toStdString().c_str(), &m_model);
	}
	catch (HException &HDevExpDefaultException) {
		QString message = HDevExpDefaultException.ErrorMessage().Text();
		return;
	}
	m_image_model = imread((m_dir + "/image.png").toLocal8Bit().toStdString(), -1);
	return;
}

void DetectionBottomMatch::saveParameter()
{
//	m_qsettings->setValue(m_section + "/" + "roi_number", m_vector_graphics_shape_rectangle.size());
//	if (m_vector_graphics_shape_rectangle.size() > 0)
//	{
//		int i = 0;
//		QRectF qrectf = m_vector_graphics_shape_rectangle[i]->boundingRect();
//		row1 = m_vector_graphics_shape_rectangle[i]->pos().y() + (int)qrectf.y();
//		column1 = m_vector_graphics_shape_rectangle[i]->pos().x() + (int)qrectf.x();
//		row2 = m_vector_graphics_shape_rectangle[i]->pos().y() + (int)(qrectf.y() + qrectf.height());
//		column2 = m_vector_graphics_shape_rectangle[i]->pos().x() + (int)(qrectf.x() + qrectf.width());
//		m_qsettings->setValue(m_section + "/" + "ROI" + QString::number(i) + "row1", row1);
//		m_qsettings->setValue(m_section + "/" + "ROI" + QString::number(i) + "column1", column1);
//		m_qsettings->setValue(m_section + "/" + "ROI" + QString::number(i) + "row2", row2);
//		m_qsettings->setValue(m_section + "/" + "ROI" + QString::number(i) + "column2", column2);
//	}

	m_score_standard = m_qdoublespinbox_score_standard->value();
	m_qsettings->setValue(m_section + "/" + "m_score_standard", m_score_standard);

	if (!QDir().exists(m_dir))
	{
		QDir().mkpath(m_dir);
	}


	

	if (m_image.empty())
	{
		QMessageBox::information(nullptr, "", "no image");
		return;
	}
	imwrite((m_dir + "/image.png").toLocal8Bit().toStdString(), m_image_model);

	try {
		if (m_model.Length() == 0)
		{
			QMessageBox::information(nullptr, "", "no model");
			return;
		}
		WriteShapeModel(m_model, (m_dir + "/model.shm").toLocal8Bit().toStdString().c_str());
	}
	catch (HException &HDevExpDefaultException) {
		QString message = HDevExpDefaultException.ErrorMessage().Text();
		QMessageBox::information(nullptr, "", message);
		return;
	}
	return;
}

bool DetectionBottomMatch::showDialog()
{
	QImage q_image = matToQImage(m_image);
	m_view->setImage(q_image, "");

	return true;
}


void DetectionBottomMatch::createModel()
{
	QString message;
	if (m_image.empty())
	{
		QMessageBox::information(nullptr, "", "no image");
		return;
	}
	try
	{
		HTuple hv_ret;
		QString message;
		HObject image = matToHImage(m_image);

        createBottomMatch(image, &m_xld_model, &hv_ret, &m_model);
//		if (m_vector_graphics_shape_rectangle.size() >= 1) {

//            createBottomMatch(image, &m_xld_model, &hv_ret, &m_model);
//		}
//		else
//		{

//            createBottomMatch(image, &m_xld_model,  &hv_ret, &m_model);
			
//		}
		int ret = hv_ret[0].I();

		if (ret > 0)
		{
			message = "Create Model OK";
		}
		else
		{
			message = "Create Model NG";
		}
	}
	catch (HException &HDevExpDefaultException)
	{
		message = HDevExpDefaultException.ErrorMessage();
	}
	m_image_model = m_image.clone();
	Mat image_show = m_image_model.clone();
	if (image_show.empty())
	{
		return;
	}
	if (image_show.channels() == 1)
	{
		cvtColor(image_show, image_show, COLOR_GRAY2BGR);
	}
	image_show = drawXld(image_show, m_xld_model, Scalar(0, 255, 0));
	QImage q_image = matToQImage(image_show);


	m_view->setImage(q_image, message);
}

void DetectionBottomMatch::showModel()
{
	Mat image_show = m_image_model.clone();
	if (image_show.empty())
	{
		return;
	}
	if (image_show.channels() == 1)
	{
		cvtColor(image_show, image_show, COLOR_GRAY2BGR);
	}
	image_show = drawXld(image_show, m_xld_model, Scalar(0, 255, 0));
	QImage q_image = matToQImage(image_show);

	m_view->setImage(q_image, "");;
}
